#!/usr/bin/python
# Created by Juan C. Espinoza <jucar.espinoza@gmail.com> January 25, 2010

import os, traceback
import argparse
from glob import glob
from joblib import Parallel, delayed
from lisn_utils import *

_path_      = os.path.dirname(os.path.abspath(__file__))
lisn_path   = '/data1/lisn/'
gps_path    = '/data1/gps/'
networks    = ['LISN', 'UNIVAP']
request = LISNRequest(debug=False)
params = request.params
hatanaka = Hatanaka()

def createfiles(opts, dt, station, dtype=None):
    '''
    '''
    print 'Processing files for site=%s and date=%s' % (station['code'],
                                                          dt.strftime('%y/%m/%d'))    
    kwargs = {} 
    kwargs['receivertype'] = station['info']['receiver']
    kwargs['receiverver'] = station['info']['receiver_firmware']
    kwargs['receivernum'] = station['info']['receiver_number']
    kwargs['antennatype'] = station['info']['antenna']
    kwargs['antennanum'] = station['info']['antenna_number']
    kwargs['xyz'] = gps.lla2xyz(*station['location'])
    kwargs['comment'] = 'Location: %s\n' % station['fullname']
    kwargs2 = {'date': dt.strftime('%y%m%d')}
    
    out = opts.output
    
    for bub in gps_names_new.values():            
        opts.old_extension     = bub[0].split('%s.')[-1]
        opts.extension         = bub[1]
        opts.label             = bub[3]
        if dtype and dtype<>bub[1]:
            continue
        rnx_name = False
        cat = False
        output = os.path.join(out, station['network'],
                                   station['code'], '%s' % dt.year,
                                   '%02d' % dt.month, bub[2])        
        try:
            if opts.decimate:
                if bub[1] in ('tec'):
                    continue
                path = os.path.join(opts.path, dt.strftime('%Y'), station['code'])
                if opts.extension=='rnx':
                    cat = True
                    data = [False]
                    file_name = '/dum'
                    files = glob(os.path.join(path, '*%s*%s' % ((dt-timedelta(1)).strftime('%y%m%d'), 'rnx')))
                    files += glob(os.path.join(path, '*%s*%s' % (dt.strftime('%y%m%d'), 'rnx')))
                    files.sort()
                    files = files[-94:]
                    if files:
                        data = read_rinex(files[0], station=station)
                        for f in files[1:]:
                            data.merge(read_rinex(f, station=station))                
                        data = data.save(output, station['code'], **kwargs)
                        file_name = data[0]
                else:                    
                    file_name = os.path.join(output, station['code'] + \
                                        dt.strftime('_%y%m%d.')+opts.extension)
                    cat = cat_files(file_name, path, dt, opts.bin_int,
                                    opts.extension, opts.old_extension, opts.label,
                                    gz=opts.gzip)
                    if opts.gzip:
                        file_name += '.gz'
                    if opts.extension=='s4' and os.path.exists(file_name):
                        scint_data = S4Data(file_name, station=station)
                        figname = file_name.replace('/scint', '/scint_figures').split('.s4')[0]+'.s4.png'
                        scint_data.plot('epoch', 's4', figname=figname, figsize=(8, 4), 
                                        s4legend=True, pkwargs={'ms':4, 'marker':'.', 'ls':''})
                if opts.server and os.path.exists(file_name):
                    req = request.update_date(station['code'], 'gps', bub[2], **kwargs2)
            elif not opts.decimate and opts.tec:
                cat = False
                path = output.replace('/tec', '/rinex')
                rnx_name = os.path.join(path, '%s%s' % (station['code'], dt.strftime('%j0.%yd.Z')))
                if os.path.exists(rnx_name):
                    rnx_data = read_rinex(rnx_name, station=station)
                else:
                    rnx_name = False
            else:
                file_names = glob(os.path.join(opts.path, '*%s*%s*' % \
                                              (dt.strftime('%y%m%d'), opts.extension)))
                if file_names:
                    file_name = file_names[0]
                    cat = True
                else:
                    cat = False
        except:
            continue
        
        if cat and opts.rinex and os.path.exists(file_name):                
            output = os.path.join(os.path.dirname(output), 'rinex')
            rnx = [False]
            old_rinex = False
            old_name = '%s%sd.Z' % (station['code'], dt.strftime('%j0.%y'))
            old_name = os.path.join(output, old_name)
            
            if os.path.exists(old_name):
                old_rinex = True
    
            try:
                if opts.extension == 'nvd':
                    rnx = nvd_to_rnx(file_name, station['code'], output,
                                     None, opts.obscodes, opts.rin_int, **kwargs)
                elif opts.extension == 'lb2':
    
                    rnx = lb2_to_rnx(file_name, station['code'], output,
                                     None, opts.obscodes, opts.rin_int, wpos=True, **kwargs)
                elif opts.extension == 'obs':
                    rnx = obs_to_rnx(file_name, station['code'], output,
                                     None, opts.obscodes, opts.rin_int, **kwargs)
                elif opts.extension == 'rnx':
                    rnx = data
            except:
                traceback.print_exc(4)
                rnx = [False]
            rnx_name = rnx[0]
    
            if rnx_name and opts.crinex:
                rnx_data = read_rinex(rnx_name, station=station)
                if old_rinex:
                    old_rinex = read_rinex(old_name)
                if hatanaka.rnx2crx:
                    rnx_name = hatanaka.compress(rnx_name, opts.gzip,
                                                      opts.remove)
                output = os.path.join(os.path.dirname(output), 'tec')
                if old_rinex:
                    print 'Merging  files old:%s new:%s' % (len(old_rinex), len(rnx_data))
                    rnx_data.merge(old_rinex)
                    ret = rnx_data.save(os.path.join(os.path.dirname(output), 'rinex'), 
                                        station['code'], **kwargs)
                    if hatanaka.rnx2crx:
                        rnx_name = hatanaka.compress(ret[0], opts.gzip,
                                                     opts.remove)
            if opts.server and rnx_name:
                req = request.update_date(station['code'], 'gps', 'rinex', **kwargs2)
        if opts.tec and rnx_name:
            try:
                rnx_data.calctec(path=_path_)
                vars = ['eqTEC', 'ltime', 'ele', 'lat', 'lon', 'sTEC', 'azi']
                tec_name = rnx_data.save_data(vars, path=output, gz=opts.gzip)
                figname = os.path.join(output.replace('/tec', '/tec_figures'), 
                                       tec_name.split('/')[-1].split('.')[0]+'.dat.png')
                rnx_data.plot('epoch', 'eqTEC', figname=figname, colormap='lat', marks=True)
                if opts.server and os.path.exists(tec_name):
                    req = request.update_date(station['code'], 'gps', 'tec', **kwargs2)
            except:
                print 'Error creating TEC'

def main():
    '''Script to decimate and concatenate raw GPS files, also you can create a
    RINEX/CRINEX observation files with -s option process server data for all
    stations.

Suported files:
Novatel files (nvd), updated files and gziped hourly files saved locally
Leica files (lb2), updated files (id37) and daily lb2 saved locally
Observable files (obs), observation files created by Gps-Scinda'''

    # parse command line options
    parser = argparse.ArgumentParser(description=main.func_doc)    
    # add options and arguments
    parser.add_argument('dates', nargs='*', default=[],
        help='Period of time to be processed (start and end date) fmt:yy,mm,dd')
    parser.add_argument('-S', '--server', action='store_true',
        help='Option usefull only for server use')
    parser.add_argument('-E', action='store', dest='extension',
        help='type of file (nvd, lb2, obs)')
    parser.add_argument('-I', action='store', default='1, 1', dest='intervals',
        help='intervals for decimation default=10,30 (10 sec for binary and 30 sec for Rinex)')
    parser.add_argument('-s', '--sites', action='store', default='',
        help='Marker Name (four char station ID)')
    parser.add_argument('-o', '--output', action='store', default=gps_path,
        help='output path for new files (default: current directory)')
    parser.add_argument('-p', '--path', action='store', default=lisn_path,
        help='source path of files of the given file type (default: current directory)')
    parser.add_argument('-D', '--decimate', action='store_true',
        help='create decimated file from binary files')
    parser.add_argument('-R', '--rinex', action='store_true',
        help='create RINEX file')
    parser.add_argument('-X', '--crinex', action='store_true',
        help='create a compresed rinex file (hatanaka)')
    parser.add_argument('-T', '--tec', action='store_true',
        help='create TEC file')
    parser.add_argument('-Z', '--gzip', action='store_true',
        help='create a gziped files')
    parser.add_argument('-r', '--remove', action='store_true',
        help='remove intermediate files')
    parser.add_argument('-O', '--obscodes', action='store', default='L1,L2,C1,P1,P2,S1,S2',
        help='Obscodes for rinex file L1,L2,P1,P2,S1,S2')        

    args = parser.parse_args()
    
    if not args.server:
        if not args.extension:
            parser.error('file type option missed')
        elif args.extension not in ('nvd', 'lb2', 'obs', 'scn', 'rnx', 'tec'):
            parser.error('Invalid data type')        
        
    args.obscodes = [x for x in args.obscodes.split(',') \
                     if x in ('L1','L2','C1','C2','P1','P2','S1','S2','D1','D2')]

    if len(args.dates)>0 :
        try:
            date_1 = GPSDateTime(args.dates[0])
            if len(args.dates) == 2:
                date_2 = GPSDateTime(args.dates[1])
            else:
                date_2 = date_1
        except:
            parser.error('Dates can not be parsed fmt: yyyy,mm,dd')
    else:
        date_1 = GPSDateTime().date()-timedelta(1)
        date_2 = date_1
    try:
        args.bin_int = 1
        args.rin_int = 1
        intervals = [int(x) for x in args.intervals.split(',') if len(x)<>0]
        args.bin_int = intervals[0]
        args.rin_int = intervals[1]
    except:
        pass 
    
    if args.server and args.extension is None:
        sites = request.stations(instrument='gps', network=','.join(networks))
    else:
        sites = request.stations(instrument='gps')
        
    if args.sites:
        sites  = [s for s in sites if s['code'] in args.sites.split(',')]
    dtype = args.extension
    while date_1<=date_2:
        #for station in sites:
        #    createfiles(args, date_1, station, dtype)
        Parallel(n_jobs=8)(delayed(createfiles)(args, date_1, site, dtype) for site in sites)    
        date_1 += timedelta(1)
    print 'Done!!!'

#Execute main routine
if __name__ == "__main__":
    dt = GPSDateTime()
    print '\n Start at %s' % dt.ctime()
    main()
    print '\n Total secs: %s' % (GPSDateTime()-dt)